/*
 * dataset.cpp
 *
 *  Created on: Feb 28, 2011
 *      Author: tqlong
 */

#include "dataset.h"
#include <fstream>
#include <cassert>

using namespace arma;

Dataset::Dataset(const std::string& fname, bool bias_ele)
  : fname_(fname), f_(fname.c_str()), bias_(bias_ele)
{
  int n;
  f_ >> n >> dim_;
  if (bias_ele) dim_++;
//  /std::cout << "n = " << n << " dim = " << dim_ << "\n";
  p_.clear();
  p_.push_back(Example(dim_));
  char line[100];
  f_.getline(line, 100);
}

void Dataset::save(const std::string& fname)
{
  std::ofstream f(fname.c_str());
  save(f);
  f.close();
}

void Dataset::save(std::ostream& f)
{
  f << p_.size() << " " << dim_ << "\n";
  for (unsigned int i = 0; i < p_.size(); i++) {
    p_[i].save(f);
    f << "\n";
  }
}

void Dataset::load(const std::string& fname, bool bias_ele)
{
  std::ifstream f(fname.c_str());
  load(f, bias_ele);
  f.close();
}

void Dataset::load(std::istream& f, bool bias_ele)
{
  int n;
  f >> n >> dim_;
  if (bias_ele) dim_++;
  std::cout << "n = " << n << " dim = " << dim_ << "\n";
  p_.clear();
  char line[100];
  f.getline(line, 100);
  for (int i = 0; i < n; i++) {
    p_.push_back(Example(dim_));
    p_.back().load(f);
    if (bias_ele) p_.back().x_[dim_-1] = 1;
    //std::cout << "y = " << y(i) << " x = " << x(i);
  }
}

bool Dataset::next()
{
  if (f_.eof()) return false;
  if (!p_.back().load(f_)) return false;
  if (bias_) p_.back().x_[dim_-1] = 1;
  //std::cout << "y = " << y() << " x = " << x();
  return true;
}

void Dataset::restart()
{
  f_.close();
  f_.open(fname_.c_str());
  int n;
  f_ >> n >> dim_;
  if (bias_) dim_++;
  //std::cout << "n = " << n << " dim = " << dim_ << "\n";
  p_.clear();
  p_.push_back(Example(dim_));
  char line[100];
  f_.getline(line, 100);
}

void Dataset::generate(int n, int d, double noise)
{
  vec w = randn(d);
  double b = randn(1)[0];
  w = w / norm(w, 2);

  dim_ = d;
  p_.clear();
  std::cout << "noise = " << noise << "\n";
  for (int i = 0; i < n; i++) {
    vec x = randu(d);
    double y = dot(w, x)+b;
    double label = y>0?1:-1;
    double r = randu(1)[0];
    if (r < noise)
      std::cout << "switch(" << i << ") ";
    if (r < noise) label = -label; // switch label
    p_.push_back(Example(x, label));
  }
}

// ============= EXAMPLE ==============
void Example::save(const std::string& fname)
{
  std::ofstream f(fname.c_str());
  save(f);
  f.close();
}

void Example::save(std::ostream& f)
{
  f << y_ << " ";
  for (unsigned int i = 0; i < x_.n_elem; i++)
    f << i << ":" << x_[i] << " ";
}

bool Example::load(const std::string& fname)
{
  std::ifstream f(fname.c_str());
  bool ret = load(f);
  f.close();
  return ret;
}

bool Example::load(std::istream& f)
{
  std::string line;
  std::getline(f, line);
  if (line.empty()) return false;
  std::stringstream s(line, ios::in);
  s >> y_;
  x_.zeros();
  while (!s.eof()) {
    unsigned int i;
    double val;
    char c;
    s >> i >> c >> val;
    assert(c == ':' && i < x_.n_elem && i >= 0);
    x_[i] = val;
  }
  return true;
}

